package ru.susu.algebra.gap.parser;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import ru.susu.algebra.matrix.Matrix;
import ru.susu.algebra.parser.BigIntegerParser;
import ru.susu.algebra.parser.IParser;
import ru.susu.algebra.properties.IPropertySource;
import ru.susu.algebra.properties.MapPropertySource;

/**
 * Парсинг матрицы из результатов работы GAP программы
 *
 * @author akargapolov
 * @since: 03.05.2010
 */
public class GapFileMatrixParser extends GapFileParserBase<Matrix>
{
	public static String VALUE_PARSER = "ValueParser";
	public static IParser<BigInteger> DEFAULT_VALUE_PARSER = new BigIntegerParser();

	private List<List<Object>> _content;
	private int _index;
	private boolean _ignore;
	private IParser<Object> _valueParser;

	public GapFileMatrixParser()
	{
		this(new MapPropertySource());
	}

	@SuppressWarnings("unchecked")
	public GapFileMatrixParser(IPropertySource props)
	{
		_valueParser = (IParser<Object>)props.getValue(VALUE_PARSER, DEFAULT_VALUE_PARSER);
	}

	@Override
	protected String getAdditionalDelimeters()
	{
		return ",";
	}

	/**
	 * Собирает результаты из {@link #_content} и возвращает их в виде матрицы
	 * @return матрица - результат
	 */
	@Override
	protected Matrix getResult()
	{
		int columns = 0;
		for (List<Object> list : _content)
		{
			columns = Math.max(columns, list.size());
		}
		Matrix result = new Matrix(_content.size(), columns);
		for (int row = 0; row < _content.size(); row++)
		{
			List<Object> list = _content.get(row);
			for (int col = 0; col < list.size(); col++)
			{
				result.setValue(row, col, list.get(col));
			}
		}
		return result;
	}

	@Override
	protected void startProcessing()
	{
		_content = null;
	}

	/**
	 * {@inheritDoc}}
	 */
	@Override
	protected void processToken(String token)
	{
		if ("[".equals(token))
		//начало новой строки
		{
			if (_content == null)
			//если это начало всей матрицы, то инициализируем контент
			{
				_content = new ArrayList<List<Object>>();
				_index = -1;
			}
			else
			//иначе добавляем новую строку
			{
				_index++;
				_content.add(new ArrayList<Object>());
				_ignore = false;
			}
		}
		else if ("]".equals(token))
		{
			//не обрабатываем закрытие
		}
		else if (!_ignore)
		//элемент матрицы
		{
			try
			{
				Object value = _valueParser.parse(token);
				_content.get(_index).add(value);
			}
			catch (Exception e)
			//считаем, что строку надо игнорировать
			{
				_content.get(_index).clear();
				_ignore = true;
			}
		}
	}
}
